home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #40 (Jan 89) / FinderControls / MPOP texte < prev    next >
Text File  |  1988-04-26  |  12KB  |  430 lines

  1. {**********************************************}
  2. { Put this file in the MPOP Project after DAPasLib. }
  3. { Don't put MacTraps that would generate unusefull glue for the Memory Manager. }
  4. { I prefer to declare DisposHandle as inline procedure : see below. }
  5. { Don't forget to "Use resource file" in "Run options" of menu "Project". }
  6. { This resource file must contain the MENU and ICN# resources }
  7. { that the PopTrap Project needs together with the compiled MDEF resource. }
  8.  
  9. { "Build and save as…" resource code of type MDEF and ID 128 in file "MPOP code" }
  10. {**********************************************}
  11. UNIT MPOP;
  12.  
  13. INTERFACE
  14.  
  15. { the name "Main" indicates to LightSpeed Pascal compiler where the entry point is }
  16.     PROCEDURE Main (message : integer;
  17.                                     theMenu : MenuHandle;
  18.                                     VAR menuRect : rect;
  19.                                     hitPt : point;
  20.                                     VAR whichItem : integer);
  21.  
  22. IMPLEMENTATION
  23.  
  24.     CONST
  25.         mPopUpMsg = 3;        { and not 4 as written in early versions of new MenuMgr }
  26.  
  27.     PROCEDURE CopyMask (srcBits, maskBits, dstBits : BitMap;
  28.                                     srcRect, maskRect, dstRect : Rect);
  29.     INLINE
  30.         $A817;
  31.  
  32.     PROCEDURE DisposHandle (h : handle);
  33. { to avoid putting the whole Memory Manager glue in our code resource  }
  34.     INLINE
  35.         $205F, $A023, $31C0, $0220;
  36.  
  37. {***************************************}
  38.  
  39. { first some utilities for reading MENU resources : }
  40.  
  41.     FUNCTION GetNextByte (VAR LongAddress : longint) : byte;
  42.     INLINE
  43.         $205F,    { MOVEA.L    (A7)+,A0     }
  44.         $2250,    { MOVEA.L    (A0),A1     }
  45.         $5290,    { ADDQ.L     #$1,(A0)     }
  46.         $204F,    { MOVEA.L    A7,A0         }
  47.         $4218,    { CLR.B      (A0)+         }
  48.         $1091;    { MOVE.B     (A1),(A0)     }
  49.  
  50.     FUNCTION GetNextInteger (VAR LongAddress : longint) : integer;
  51.     INLINE
  52.         $205F,    { MOVEA.L    (A7)+,A0         }
  53.         $2250,    { MOVEA.L    (A0),A1         }
  54.         $5490,    { ADDQ.L     #$2,(A0)         }
  55.         $204F,    { MOVEA.L   A7,A0             }
  56.         $10D9,    { MOVE.B     (A1)+,(A0)+    }
  57.         $1091;    { MOVE.B     (A1),(A0)         }
  58.  
  59.     FUNCTION GetNextString (VAR LongAddress : longint) : StringHandle;
  60. { returns NIL if allocation failed }
  61.     INLINE
  62.         $205F,                { MOVEA.L    (A7)+,A0        ;A0:=@LongAddress }
  63.         $2250,                { MOVEA.L    (A0),A1        ;A1:=LongAddress }
  64.         $7000,                { MOVEQ      #$00,D0        ;countChars:=0 }
  65.         $1011,                { MOVE.B     (A1),D0            ;countChars:=LongAddress^ }
  66.         $2200,                { MOVE.L     D0,D1            ;save countChars }
  67.         $5200,                { ADDQ.B     #$1,D0            ;length:=countChars+1 }
  68.         $D190,                { ADD.L      D0,(A0)            ;FuturLongAddress:=LongAddress+length }
  69.         $A122,                { OSTRAP     $A122            ;A0:=NewHandle(D0=length) }
  70.         $4A80,                { TST.L      D0                    ;if MemError }
  71.         $660C,                { BNE.S      *+$000E            ;<>0 goto error }
  72.         $2E88,                { MOVE.L     A0,(A7)            ;GetChaine:=A0 }
  73.         $2050,                { MOVEA.L    (A0),A0        ;StringPtr }
  74.                         { loop                                ;repeat }
  75.         $10D9,                { MOVE.B     (A1)+,(A0)+    ;StringPtr^:=LongAddress^ }
  76.         $51C9, $FFFC,        { DBF        D1,*-$0002        ;dec(length); until length<0 }
  77.         $6002,                { BRA.S      *+$0004        ;goto bottom }
  78.                         { error }
  79.         $4297;                { CLR.L      (A7)                ;GetChaine:=NIL }
  80.                         { bottom }
  81.  
  82.     FUNCTION SkipNextString (VAR LongAddress : longint) : byte;
  83.         VAR
  84.             length : byte;
  85.     BEGIN
  86.         length := GetNextByte(LongAddress);
  87.         LongAddress := LongAddress + length;
  88.         SkipNextString := length;
  89.     END;
  90.  
  91.     PROCEDURE SkipBytes (VAR LongAddress : longint;
  92.                                     byteCount : integer);
  93.     BEGIN
  94.         LongAddress := LongAddress + byteCount;
  95.     END;
  96.  
  97. {***************************************}
  98.  
  99.     PROCEDURE Main;
  100.  
  101.         FUNCTION GetItemCenter : point;
  102. { returns the ItemCenter in local coordinates, relative to menuRect }
  103. { theMenu is allready locked }
  104.             VAR
  105.                 LongAddress : longint;
  106.                 length : byte;
  107.                 i : integer;
  108.                 ItemCenter : point;
  109.         BEGIN
  110.             LongAddress := ord(theMenu^) + 14;
  111.             length := SkipNextString(LongAddress);
  112.             i := 0;
  113.             REPEAT
  114.                 i := i + 1;
  115.                 length := SkipNextString(LongAddress);
  116.                 IF length > 0 THEN
  117.                     BEGIN
  118.                         IF i = whichItem THEN
  119.                             BEGIN
  120.                                 ItemCenter.v := GetNextInteger(LongAddress);
  121.                                 ItemCenter.h := GetNextInteger(LongAddress);
  122.                             END
  123.                         ELSE
  124.                             BEGIN
  125.                                 SkipBytes(LongAddress, 4);
  126.                             END;
  127.                     END
  128.                 ELSE        { if length<=0 : }
  129.                     SetPt(ItemCenter, 0, 0);
  130.             UNTIL (length <= 0) OR (i = whichItem);
  131.             GetItemCenter := ItemCenter;
  132.         END;
  133.  
  134. {***************************************}
  135.  
  136.         PROCEDURE DoDrawMessage;
  137.  
  138.             PROCEDURE PinString (theString : Str255;
  139.                                             center : point);
  140.             BEGIN
  141.                 WITH center DO
  142.                     MoveTo(h - StringWidth(theString) DIV 2, v);
  143.                 DrawString(theString);
  144.             END;
  145.  
  146.             PROCEDURE PlotIconDataCopy (theIcon : handle;
  147.                                             dstSquare : rect);
  148.                 VAR
  149.                     srcSquare : rect;
  150.                     data : bitmap;
  151.                     myPort : GrafPtr;
  152.             BEGIN
  153.                 IF (theIcon <> NIL) THEN
  154.                     BEGIN
  155.                         SetRect(srcSquare, -16, -16, 16, 16);
  156.                         data.rowBytes := 4;
  157.                         data.baseAddr := ptr(theIcon^);
  158.                         data.bounds := srcSquare;
  159.                         GetPort(myPort);
  160.                         CopyBits(data, myPort^.portbits, srcSquare, dstSquare, srcCopy, NIL);
  161.                     END;
  162.             END;
  163.  
  164.             VAR
  165.                 IconRect : rect;
  166.                 IconName : StringHandle;
  167.                 LongAddress : longint;
  168.                 NameLength : byte;
  169.                 ItemCenter, TextCenter : point;
  170.                 theIcon : handle;
  171.         BEGIN
  172.             LongAddress := ord(theMenu^) + 14;
  173.             NameLength := SkipNextString(LongAddress);
  174.             REPEAT
  175.                 IconName := GetNextString(LongAddress);
  176.                 NameLength := length(IconName^^);
  177.                 IF NameLength > 0 THEN
  178.                     BEGIN
  179.                         theIcon := GetNamedResource('ICN#', IconName^^);
  180.                         ItemCenter.v := GetNextInteger(LongAddress) + menuRect.top;
  181.                         ItemCenter.h := GetNextInteger(LongAddress) + menuRect.left;
  182.                         WITH ItemCenter DO
  183.                             BEGIN
  184.                                 SetRect(IconRect, h - 16, v - 21, h + 16, v + 11);
  185.                                 SetPt(TextCenter, h, v + 20);
  186.                             END;
  187.                         PlotIconDataCopy(theIcon, IconRect);
  188.                         TextFont(geneva);
  189.                         TextSize(9);
  190.                         PinString(IconName^^, TextCenter);
  191.                         TextFont(systemFont);
  192.                         TextSize(12);
  193.                     END;
  194.                 DisposHandle(handle(IconName));
  195.             UNTIL NameLength <= 0;
  196.         END;                { of DoDrawMessage }
  197.  
  198. {***************************************}
  199.  
  200.         PROCEDURE DoChooseMessage;
  201.  
  202.             FUNCTION GetIconRect : rect;
  203. { returns the IconRect in global coordinates }
  204.                 VAR
  205.                     ItemCenter : point;
  206.                     IconRect : rect;
  207.             BEGIN
  208.                 ItemCenter := GetItemCenter;
  209.                 WITH ItemCenter DO
  210.                     BEGIN
  211.                         IF (h = 0) AND (v = 0) THEN
  212.                             SetRect(IconRect, 0, 0, 0, 0)
  213.                         ELSE
  214.                             SetRect(IconRect, h - 16, v - 21, h + 16, v + 11);
  215.                     END;
  216.                 WITH menuRect DO
  217.                     OffSetRect(IconRect, left, top);
  218.                 GetIconRect := IconRect;
  219.             END;            { of GetIconRect }
  220.  
  221.             PROCEDURE PlotIconMaskXor (theIcon : handle;
  222.                                             dstSquare : rect);
  223.                 VAR
  224.                     srcSquare : rect;
  225.                     mask : bitmap;
  226.                     myPort : GrafPtr;
  227.             BEGIN
  228.                 IF (theIcon <> NIL) THEN
  229.                     BEGIN
  230.                         SetRect(srcSquare, -16, -16, 16, 16);
  231.                         mask.rowBytes := 4;
  232.                         mask.baseAddr := ptr(ord4(theIcon^) + 128);
  233.                         mask.bounds := srcSquare;
  234.                         GetPort(myPort);
  235.                         CopyBits(mask, myPort^.portbits, srcSquare, dstSquare, srcXOr, NIL);
  236.                     END;
  237.             END;                { of PlotIconMaskXor }
  238.  
  239.             FUNCTION GetIconName (whichItem : integer) : StringHandle;
  240. { theMenu is allready locked }
  241.                 VAR
  242.                     LongAddress : longint;
  243.                     length : byte;
  244.                     i : integer;
  245.                     IconName : StringHandle;
  246.             BEGIN
  247.                 LongAddress := ord(theMenu^) + 14;
  248.                 length := SkipNextString(LongAddress);
  249.                 i := 0;
  250.                 REPEAT
  251.                     i := i + 1;
  252.                     IF i = whichItem THEN
  253.                         BEGIN
  254.                             IconName := GetNextString(LongAddress);
  255.                         END
  256.                     ELSE
  257.                         BEGIN
  258.                             length := SkipNextString(LongAddress);
  259.                             IF length > 0 THEN
  260.                                 SkipBytes(LongAddress, 4)
  261.                             ELSE
  262.                                 IconName := NIL;
  263.                         END;
  264.                 UNTIL (length <= 0) OR (i = whichItem);
  265.                 GetIconName := IconName;
  266.             END;
  267.  
  268.             PROCEDURE InvertIcon (whichItem : integer;
  269.                                             dstSquare : rect);
  270.                 VAR
  271.                     IconName : StringHandle;
  272.                     myIcon : handle;
  273.             BEGIN
  274.                 IconName := GetIconName(whichItem);
  275.                 myIcon := GetNamedResource('ICN#', IconName^^);
  276.                 PlotIconMaskXor(myIcon, dstSquare);
  277.             END;
  278.  
  279.             VAR
  280.                 itemNumber : integer;
  281.                 NameLength : byte;
  282.                 LongAddress : longint;
  283.                 ItemCenter : point;
  284.                 ItemRect, OldIconRect, IconRect : rect;
  285.         BEGIN                { DoChooseMessage }
  286.             LongAddress := ord(theMenu^) + 14;
  287.             NameLength := SkipNextString(LongAddress);
  288.             itemNumber := 0;
  289.             REPEAT
  290.                 itemNumber := itemNumber + 1;
  291.                 NameLength := SkipNextString(LongAddress);
  292.                 IF NameLength > 0 THEN
  293.                     BEGIN
  294.                         ItemCenter.v := GetNextInteger(LongAddress);
  295.                         ItemCenter.h := GetNextInteger(LongAddress);
  296.                         WITH ItemCenter DO
  297.                             SetRect(ItemRect, h - 25, v - 25, h + 25, v + 25);
  298.                         WITH menuRect DO
  299.                             OffSetRect(ItemRect, left, top);
  300.                     END;
  301.             UNTIL (NameLength <= 0) OR (PtInRect(hitPt, ItemRect));
  302.             IF NameLength <= 0 THEN        { hitPt is not in any item }
  303.                 BEGIN
  304.                     IF whichItem <> 0 THEN
  305.                         BEGIN
  306.                             InvertIcon(whichItem, GetIconRect);
  307.                             whichItem := 0;
  308.                         END;
  309.                 END
  310.             ELSE IF itemNumber <> whichItem THEN                            { hitPt is in itemRect }
  311.                 BEGIN
  312.                     IF whichItem <> 0 THEN
  313.                         InvertIcon(whichItem, GetIconRect);
  314.                     WITH ItemCenter DO
  315.                         SetRect(IconRect, h - 16, v - 21, h + 16, v + 11);
  316.                     WITH MenuRect DO
  317.                         OffSetRect(IconRect, left, top);
  318.                     InvertIcon(itemNumber, IconRect);
  319.                     whichItem := itemNumber;
  320.                 END;
  321.         END;                { of DoChooseMessage }
  322.  
  323. {***************************************}
  324.  
  325.         PROCEDURE DoSizeMessage;
  326. { theMenu is allready locked }
  327.  
  328.             PROCEDURE RectAndPt (VAR theRect : rect;
  329.                                             thePoint : point);
  330.             BEGIN
  331.                 WITH theRect, thePoint DO
  332. { we suppose that 0=left<right and 0=top<bottom }
  333.                     BEGIN
  334.                         IF h > right THEN
  335.                             right := h;
  336.                         IF v > bottom THEN
  337.                             bottom := v;
  338.                     END;
  339.             END;
  340.  
  341.             VAR
  342.                 LongAddress : longint;
  343.                 length : byte;
  344.                 ItemCenter : point;
  345.                 Envelope : rect;
  346.         BEGIN
  347.             LongAddress := ord(theMenu^) + 14;
  348.             length := SkipNextString(LongAddress);
  349.             SetRect(Envelope, 0, 0, 0, 0);
  350.             REPEAT
  351.                 length := SkipNextString(LongAddress);
  352.                 IF length > 0 THEN
  353.                     BEGIN
  354.                         ItemCenter.v := GetNextInteger(LongAddress);
  355.                         ItemCenter.h := GetNextInteger(LongAddress);
  356.                         RectAndPt(envelope, ItemCenter);
  357.                     END
  358.             UNTIL (length <= 0);
  359.             WITH theMenu^^, envelope DO
  360.                 BEGIN
  361.                     menuWidth := right + 25;
  362.                     menuHeight := bottom + 25;
  363.                 END;
  364.         END;            { of DoSizeMessage }
  365.  
  366. {***************************************}
  367.  
  368.         PROCEDURE DoPopUpMessage;
  369. { on entry:        whichItem(=popUpItem) , }
  370. {                    hitPt (= center of title icon) }
  371. {                    theMenu (Locked) }
  372. { on exit : menuRect }
  373. { ThePort is allready set to WindowManager Port }
  374.             VAR
  375.                 ItemCenter, IconCenter : point;
  376.                 dh, dv : integer;
  377.                 WMPort : GrafPtr;
  378.                 mBarHeight : ^integer;
  379.         BEGIN
  380.             mBarHeight := pointer($BAA);
  381.             WITH theMenu^^, hitPt DO
  382.                 SetRect(menuRect, h, v, h + menuWidth, v + MenuHeight);
  383.             IF whichItem > 0 THEN
  384.                 BEGIN
  385.                     ItemCenter := GetItemCenter;
  386.                     WITH ItemCenter DO
  387.                         SetPt(IconCenter, h, v - 5);
  388.                     WITH IconCenter DO
  389.                         IF NOT ((h = 0) AND (v = 0)) THEN
  390.                             OffSetRect(menuRect, -h, -v)
  391.                         ELSE
  392.                             whichItem := 0;
  393.                 END;
  394.             IF whichItem <= 0 THEN
  395.                 OffSetRect(menuRect, -25, +25);
  396.             GetPort(WMPort);
  397.             WITH WMPort^ DO
  398.                 BEGIN
  399.                     IF menuRect.right + 8 > PortRect.right THEN
  400.                         dh := PortRect.right - menuRect.right - 8
  401.                     ELSE IF menuRect.left - 8 < PortRect.left THEN
  402.                         dh := PortRect.left - menuRect.left + 8
  403.                     ELSE
  404.                         dh := 0;
  405.                     IF menuRect.bottom + 8 > PortRect.bottom THEN
  406.                         dv := PortRect.bottom - menuRect.bottom - 8
  407.                     ELSE IF menuRect.top - 8 < PortRect.top + mBarHeight^ THEN
  408.                         dv := PortRect.top + mBarHeight^ - menuRect.top + 8
  409.                     ELSE
  410.                         dv := 0;
  411.                 END;
  412.             OffSetRect(menuRect, dh, dv);
  413.         END;                { of DoPopUpMessage }
  414.  
  415. {***************************************}
  416.  
  417.     BEGIN                { of Main }
  418.         CASE message OF
  419.             mSizeMsg : 
  420.                 DoSizeMessage;
  421.             mDrawMsg : 
  422.                 DoDrawMessage;
  423.             mChooseMsg : 
  424.                 DoChooseMessage;
  425.             mPopUpMsg : 
  426.                 DoPopUpMessage;
  427.         END;
  428.     END;
  429.  
  430. END.